﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Collections.ObjectModel;
using System.Collections;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Diagnostics;
using System.Globalization;

namespace Microsoft.Office.Project.EPMAuditing.Library
{
    public class MessageSegmentCollection : IEnumerable
    {
        private Collection<MessageSegment> _messages;
        private int _segmentCount;  // Zero based
        //private byte[] _message;
        private const int MAX_MESSAGE_SIZE = 16000;
        private Guid _messageUid;

        public MessageSegmentCollection(Guid messageUid, int segmentCount)
        {
            _messageUid = messageUid;
            _segmentCount = segmentCount;
            _messages = new Collection<MessageSegment>();
        }

        public MessageSegmentCollection(MemoryStream message)
        {
            Debug.Listeners.Add(new TextWriterTraceListener(@"c:\MessageSegments.txt"));
            Debug.AutoFlush = true;
            _messages = new Collection<MessageSegment>();
            _messageUid = Guid.NewGuid();
            _segmentCount = ((int)message.Length / MAX_MESSAGE_SIZE) + 1;
            message.Position = 0;
            Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0}  segment Count:{1}, Length:{2}", DateTime.Now.ToString(), _segmentCount.ToString(), message.Length.ToString()));
            for (int i = 0; i < _segmentCount; i++)
            {
                byte[] myBuffer = new byte[MAX_MESSAGE_SIZE];
                Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0}  READ segment: {1}  start:{2}", DateTime.Now.ToString(), i.ToString(), (i * MAX_MESSAGE_SIZE).ToString()));
                message.Read(myBuffer, 0, MAX_MESSAGE_SIZE);
                _messages.Add(new MessageSegment(myBuffer, _messageUid, i, _segmentCount));
            }
        }

        public IEnumerator GetEnumerator()
        {
            return _messages.GetEnumerator();
        }

        public void Add(MessageSegment ms)
        {
            if (ms.MessageUid == _messageUid)
                _messages.Add(new MessageSegment(ms));
        }

        public void Clear()
        {
            _messages.Clear();
        }

        public bool MessageComplete
        {
            get
            {
                if (_messages.Count == _segmentCount)
                    return true;
                else
                    return false;
            }
        }

        public MemoryStream Message
        {
            get
            {
                if (MessageComplete)
                {
                    MemoryStream memstr = new MemoryStream();
                    foreach (MessageSegment ms in _messages)
                    {
                        memstr.Write(ms.Message, 0, MAX_MESSAGE_SIZE);
                    }
                    return memstr;
                }
                else
                    return null;

            }
        }

        public Guid MessageUid
        {
            get { return _messageUid; }
        }

        public int SegmentCount
        {
            get { return _segmentCount; }
        }



    }

    [Serializable]
    public class MessageSegment
    {
        private Guid _messageUid;
        private int _segmentNumber;
        private int _segmentCount;
        private byte[] _message;

        //public MessageSegment() { }

        public MessageSegment(MemoryStream ms)
        {
            IFormatter formatter = new BinaryFormatter();
            MessageSegment msgseg = (MessageSegment)formatter.Deserialize(ms);
            Message = msgseg.Message;
            MessageUid = msgseg.MessageUid;
            SegmentNumber = msgseg.SegmentNumber;
            SegmentCount = msgseg.SegmentCount;
            ms.Close();
        }
        public MessageSegment(byte[] message, Guid messageUid, int segmentNumber, int segmentCount)
        {
            MessageUid = messageUid;
            SegmentNumber = segmentNumber;
            SegmentCount = segmentCount;
            _message = new byte[message.Length];
            Array.Copy(message, message.GetLowerBound(0), _message, _message.GetLowerBound(0), message.Length);
        }

        public MessageSegment(MessageSegment ms)
        {
            MessageUid = ms.MessageUid;
            SegmentNumber = ms.SegmentNumber;
            SegmentCount = ms.SegmentCount;
            _message = new byte[ms.Message.Length];
            Array.Copy(ms.Message, ms.Message.GetLowerBound(0), _message, _message.GetLowerBound(0), ms.Message.Length);
        }

        public byte[] ToArray()
        {
            IFormatter formatter = new BinaryFormatter();
            MemoryStream ms = new MemoryStream();
            formatter.Serialize(ms, this);
            byte[] bytes = ms.ToArray();
            ms.Close();
            return bytes;
        }

        public Guid MessageUid
        {
            get { return _messageUid; }
            set { _messageUid = value; }
        }

        public int SegmentNumber
        {
            get { return _segmentNumber; }
            set { _segmentNumber = value; }
        }

        public int SegmentCount
        {
            get { return _segmentCount; }
            set { _segmentCount = value; }
        }

        public byte[] Message
        {
            get { return _message; }
            set { _message = value; }
        }


    }
}
